package pl.zuiol.games.poker.util;

import pl.zuiol.games.poker.Dealer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * User: Damian
 * Date: 06.08.11
 * Time: 14:48
 */
public class HandValuator {

    private List<Card> allCards;
    private Hand hand;

    public HandValuator(){

        allCards = new ArrayList<Card>();
    }

    public HandValue valuateHand(Hand hand, TableSet tableSet){

        Card[] cards = new Card[]{new Card(Rank.Two, Suit.Hearts), new Card(Rank.Two, Suit.Clubs),
        new Card(Rank.Two, Suit.Spades), new Card(Rank.Two, Suit.Diamonds), new Card(Rank.Two, Suit.Hearts)};
        HandValue tempHandValue = new HandValue(HandValue.Category.HIGH_CARD, cards);
        this.hand = hand;
        allCards.addAll(hand.getCards());
        allCards.addAll(tableSet.getTableSet());

        List<Card[]> possibleHand = getPossibleHands(allCards);
        for (Card[] ph : possibleHand){
            if(isStraightFlush(ph)){
                System.out.println("Straight Flush");
                HandValue handValue = new HandValue(HandValue.Category.STRAIGHT_FLUSH, ph);
                if(tempHandValue.compareTo(handValue) <= 0)
                    tempHandValue = handValue;
                continue;
            }

            if(isFourOfAKind(ph)){
                System.out.println("Four of kind");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.FOUR_OF_KIND) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.FOUR_OF_KIND, ph);
                continue;
            }

            if(isFullHouse(ph)){
                System.out.println("Full house");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.FULL_HOUSE) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.FULL_HOUSE, ph);
                continue;
            }

            if(isFlush(ph)){
                System.out.println("Flush");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.FLUSH) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.FLUSH, ph);
                continue;
            }

            if(isStraight(ph)){
                System.out.println("Straight");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.STRAIGHT) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.STRAIGHT, ph);
                continue;
            }

            if(isThreeOfAKind(ph)) {
                System.out.println("Three of Kind");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.THREE_OF_KIND) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.THREE_OF_KIND, ph);
                continue;
            }

            if(isTwoPairs(ph)){
                System.out.println("Two Pairs");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.TWO_PAIRS) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.TWO_PAIRS, ph);
                continue;
            }

            if(isPair(ph)){
                System.out.println("Pair");
                if(tempHandValue.getCategory().compareTo(HandValue.Category.PAIR) <= 0)
                    tempHandValue = new HandValue(HandValue.Category.PAIR, ph);
                continue;
            }


        }

        return tempHandValue;
    }

    private List<Card[]> getPossibleHands(List<Card> allCards){

        List<Card[]> listOfPossibleHands = new ArrayList<Card[]>();
        int k = 5;
        int n = 7;

        int[] tab = new int[k + 1];
        for(int i = 1; i <= k; i++){
            tab[i] = i;
        }
        int p = k;
        while (p >= 1)
        {

            Card[] hand = new Card[] {allCards.get(tab[1]- 1), allCards.get(tab[2]- 1), allCards.get(tab[3]- 1), allCards.get(tab[4]- 1), allCards.get(tab[5]- 1)};
            List<Card> listCards = new ArrayList<Card>();
            Collections.addAll(listCards, hand);
            Collections.sort(listCards);
            for(Card card : listCards){
            System.out.print(card.toString() + "  ");
        }
            listOfPossibleHands.add(listCards.toArray(hand));
            System.out.println(tab[1] + " " + tab[2] + " " + tab[3] + " " + tab[4] + " " + tab[5]);
            if(tab[k] == n)
                p = p - 1;
            else
                p = k;
            if(p >= 1){
                for( int i = k; i >= p; i--){
                    tab[i] = tab[p] + i - p +1;
                }
            }
        }
        listOfPossibleHands.remove(listOfPossibleHands.size() - 1);
        return listOfPossibleHands;
    }

    public static void main(String[] args){

        HandValuator val = new HandValuator();
        Deck deck = new Deck();
        Hand hand = new Hand(deck.drawFromDeck(), deck.drawFromDeck());
        TableSet tableSet = new TableSet(deck);
        tableSet.floop();
        tableSet.turn();
        tableSet.river();
        HandValue hv = val.valuateHand(hand, tableSet);

        for(Card card : val.allCards){
            System.out.print(card.toString() + "  ");
        }

    }

    private boolean isStraightFlush(Card[] myHand)
	{
		for(int i = 0; i < myHand.length - 1; i++)
		{
			if(myHand[i].getSuit() != myHand[i+1].getSuit())
				return false;

			if(	myHand[i].compareTo(myHand[i+1]) != -1
				&&
				( myHand[i+1].getRank() != Rank.Ace
				||   myHand[i].getRank() != Rank.Five)
			)
				return false;
		}

		return true;
	}

	private boolean isFourOfAKind(Card[] myHand)
	{
		int c = 0;

		if(myHand[0].compareTo(myHand[1]) == 0)
			c++;

		for(int i = 1; i < myHand.length - 1; i++)
			if(myHand[i].compareTo(myHand[i+1]) == 0)
				c++;
			else
				break;

		return (c >= 3);
	}

	private boolean isFullHouse(Card[] myCards)
	{
		if(myCards[0].compareTo(myCards[1]) != 0)
			return false;

		if(myCards[3].compareTo(myCards[4]) != 0)
			return false;

		if(		myCards[2].compareTo(myCards[1]) != 0
			&&  myCards[2].compareTo(myCards[3]) != 0
		)
			return false;

		return true;
	}

	private boolean isFlush(Card[] myHand)
	{
		for(int i = 0; i < myHand.length - 1; i++)
		{
			if(myHand[i].getSuit() != myHand[i+1].getSuit())
				return false;
		}

		return true;
	}

	private boolean isStraight(Card[] myHand)
	{
		for(int i = 0; i < myHand.length - 1; i++)
			if(	myHand[i].compareTo(myHand[i+1]) != -1
				&& ( myHand[i+1].getRank() != Rank.Ace
				|| myHand[i].getRank() != Rank.Five)
			)
				return false;
		return true;
	}

	private boolean isThreeOfAKind(Card[] myCards)
	{
		if(myCards[2].compareTo(myCards[1]) != 0)
		{
			if(myCards[2].compareTo(myCards[3]) != 0)
				return false;

			if(myCards[2].compareTo(myCards[4]) != 0)
				return false;
		}
		else
		{
			if(		myCards[2].compareTo(myCards[3]) != 0
				&&	myCards[2].compareTo(myCards[0]) != 0)
				return false;
		}

		return true;
	}

	private boolean isTwoPairs(Card[] myCards)
	{
		if(myCards[0].compareTo(myCards[1]) != 0)
		{
			if(		myCards[1].compareTo(myCards[2]) != 0
				||	myCards[3].compareTo(myCards[4]) != 0)
				return false;
		}
		else
		{
			if(		myCards[2].compareTo(myCards[3])!= 0
				&&	myCards[3].compareTo(myCards[4])!= 0)
				return false;
		}

		return true;
	}

	private boolean isPair(Card[] myCards)
	{
		for(int i = 0; i < myCards.length - 1; i++)
			if(myCards[i].compareTo(myCards[i+1]) == 0)
				return true;

		return false;
	}
}
